<?php

namespace Fox;

class DataBase {

	public $pdo;

	public $prefix;

	public $table = '_fox_';

	function __construct($cf) {
		$this->pdo = self::_poll($cf);
		$this->prefix = isset($cf['prefix']) ? $cf['prefix'] : '';
	}

	private static function _poll($cf) {
		static $exist_pdo = [];
		if (!isset($exist_pdo[$cf['dsn']])) {
			$pdo = isset($cf['options']) ? (new \PDO($cf['dsn'], $cf['user'], $cf['pwd'], $cf['options'])) :
			(new \PDO($cf['dsn'], $cf['user'], $cf['pwd']));
			$pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
			$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
			$pdo->exec("set names " . (isset($cf['charset']) ? $cf['charset'] : 'utf8'));
			$exist_pdo[$cf['dsn']] = $pdo;
		}
		return $exist_pdo[$cf['dsn']];
	}

	/**
	 * 开启事务
	 */
	public function beginTransaction() {
		$this->pdo->beginTransaction();
	}

	/**
	 * 提交事务
	 */
	public function commit() {
		$this->pdo->commit();
	}

	/**
	 * 回滚事务
	 */
	public function rollBack() {
		$this->pdo->rollBack();
	}

	/**
	 * 设置当前操作的表
	 * @param $table
	 * @return $this
	 */
	public function table($table) {
		$this->table = $this->prefix . $table;
		return $this;
	}

	public $beg = -1;
	public $len = -1;

	public function limit($beg, $len = -1) {
		$this->beg = $beg;
		$this->len = $len;
		return $this;
	}

	/**
	 * 插入数据到数据库
	 * @param $data
	 * @return int|false
	 */
	public function insert($data) {
		$inputs = [];
		$fields = [];
		$qs = [];
		foreach ($data as $key => $val) {
			$fields[] = "`$key`";
			$qs[] = '?';
			$inputs[] = $val;
		}
		$sql = "insert into $this->table(" . join(',', $fields) . ') values(' . join(',', $qs) . ')';
		return $this->rowCount($sql, $inputs);
	}

	/**
	 * 更新数据库记录
	 * @param $data
	 * @param $where id或者where条件
	 * @param bool|false $inputs sql参数值
	 * @return int|false
	 */
	public function update($data, $where, $inputs = false) {
		$arr = [];
		$fields = [];
		foreach ($data as $key => $val) {
			$fields[] = " `$key` = ? ";
			$arr[] = $val;
		}
		$where = $this->parse_where($where, $inputs);
		$sql = "update $this->table set " . join(',', $fields) . " where $where";
		return $this->rowCount($sql, is_array($inputs) ? array_merge($arr, $inputs) : $arr);
	}

	public function rowCount($sql, $inputs) {
		$result = $this->execute($sql, $inputs);
		return $result === false ? false : $result->rowCount();
	}

	private function parse_where($where, &$inputs) {

		if (is_numeric($where)) {
			return " `id` = $where ";
		} elseif (is_array($where)) {

			$fields = [];
			foreach ($where as $key => $val) {
				$inputs[] = $val;
				$fields[] = " `$key` = ? ";
			}

			return join('and', $fields);

		} else {
			return $where;
		}

	}

	/**
	 * 删除数据库记录
	 * @param $where id或者where条件
	 * @param bool|false $inputs sql参数值
	 * @return int|false
	 */
	public function delete($where, $inputs = false) {
		$where = $this->parse_where($where, $inputs);
		$sql = "delete from $this->table where $where";
		return $this->rowCount($sql, $inputs);
	}

	/**
	 * 获取数据库一条记录
	 * @param $where id或者where条件
	 * @param bool|false $inputs sql参数值 如果该值为字符串，则视为 $field
	 * @param string $field
	 * @return val|false
	 */
	public function get($where, $inputs = false, $field = '*') {
		if (is_string($inputs)) {
			$field = $inputs;
			$inputs = [];
		}
		$where = $this->parse_where($where, $inputs);
		$sql = "select $field from  $this->table where $where limit 1";

		$result = $this->execute($sql, $inputs);
		return $result === false ? false : $result->fetch(\PDO::FETCH_ASSOC);
	}

	/**
	 * 获取第一行第一个值
	 * @param $where id或者where条件
	 * @param bool|false $inputs sql参数值
	 * @param string $field
	 * @return val|bool
	 */
	public function value($where, $inputs = false, $field = '*') {
		if (is_string($inputs)) {
			$field = $inputs;
			$inputs = [];
		}
		$where = $this->parse_where($where, $input);
		$sql = "select $field from  $this->table where $where limit 1";

		$result = $this->execute($sql, $inputs);
		if ($result === false) {
			return false;
		}
		$ret = $result->fetch(\PDO::FETCH_NUM);
		return $ret === false ? false : $ret[0];
	}

	/**
	 * 根据where条件获取记录集
	 * @param $where where条件
	 * @param bool|false $inputs sql参数值
	 * @param string $field
	 * @return array|false
	 */
	public function find($where, $inputs = false, $field = '*') {
		if (is_string($inputs)) {
			$field = $inputs;
			$inputs = [];
		}
		$where = $this->parse_where($where, $inputs);
		$sql = "select $field from  $this->table where $where";
		if ($this->beg != -1) {
			$sql .= " limit $this->beg";
		}
		if ($this->len != -1) {
			$sql .= " ,$this->len";
		}

		return $this->select($sql, $inputs);
	}

	const FETCH_STYLE_KV = -12345;

	/**
	 * @param $where
	 * @param bool|false $inputs
	 * @param string $field
	 * @return array 如果查询结果中只有2个字段，那么返回 field1=>field2 结构，如果大于2个字段则返回 field1=>Row 结构
	 */
	public function kv($where, $inputs = false, $field = '*') {
		if (is_string($inputs)) {
			$field = $inputs;
			$inputs = [];
		}
		$where = $this->parse_where($where, $inputs);
		$sql = "select $field from  $this->table where $where";
		if ($this->beg != -1) {
			$sql .= " limit $this->beg";
		}
		if ($this->len != -1) {
			$sql .= " ,$this->len";
		}
		return $this->select($sql, $inputs, DataBase::FETCH_STYLE_KV);
	}

	/**
	 * @param $where
	 * @param bool|false $inputs
	 * @param string $field
	 * @return array 返回第一列的纯数组
	 */
	public function arr($where, $inputs = false, $field = '*') {
		if (is_string($inputs)) {
			$field = $inputs;
			$inputs = [];
		}
		$where = $this->parse_where($where, $inputs);
		$sql = "select $field from  $this->table where $where";
		if ($this->beg != -1) {
			$sql .= " limit $this->beg";
		}
		if ($this->len != -1) {
			$sql .= " ,$this->len";
		}
		return $this->select($sql, $inputs, \PDO::FETCH_COLUMN);
	}

	/**
	 * 根据sql语句获取所有记录
	 * @param $sql
	 * @param bool|false $inputs
	 * @param $[fetch_style] [<description>]
	 * @return array|false
	 */
	public function select($sql, $inputs = false, $fetch_style = \PDO::FETCH_ASSOC) {
		if (is_int($inputs)) {
			$fetch_style = $inputs;
			$inputs = [];
		}
		$result = $this->execute($sql, $inputs);

		if ($fetch_style == DataBase::FETCH_STYLE_KV) {
			if ($result->columnCount() == 2) {
				$fetch_style = \PDO::FETCH_KEY_PAIR;
			} else {
				$fetch_style = \PDO::FETCH_UNIQUE | \PDO::FETCH_ASSOC;
			}
		}
		return $result === false ? false : $result->fetchAll($fetch_style);
	}

	private $result;

	/**
	 * 执行一条sql语句
	 * @param $sql
	 * @param $inputs sql参数值
	 * @return PDOStatement|false
	 */
	public function execute($sql, $inputs = false) {
		$GLOBALS['_last_db_'] = $this;
		$this->sql = $sql;
		$this->inputs = $inputs;
		if (($this->result = $this->pdo->prepare($sql)) !== false) {
			is_array($inputs) && !empty($inputs) ? $this->result->execute($inputs) : $this->result->execute();
		}
		return $this->result;
	}

	private $sql;

	private $inputs;

	public function printError() {
		echo '<pre>SQL Info: ';
		print_r(array(
			'sql' => $this->sql,
			'inputs' => $this->inputs,
		));
		echo '</pre>';
	}

	/**
	 * 数据库最后id
	 * @return string
	 */
	public function lastId() {
		return $this->pdo->lastInsertId();
	}

	private $error_info;

	/**
	 * 数据库最后语句的错误信息
	 * @return mixed
	 */
	public function errorInfo() {
		return $this->error_info;
	}

	public function __destruct() {
		if ($this->pdo) {
			unset($this->pdo);
		}
		if ($this->result) {
			unset($this->result);
		}
	}

}
